package com.zjw.zy.heart.service.impl;

import com.zjw.zy.heart.service.IC2CTransService;
import com.zjw.zy.heart.userpool.IUserPool;
import com.zjw.zy.heart.utils.LogUtils;
import com.zjw.zy.heart.wbsocket.IWSConnectHandler;
import com.zjw.zy.heart.wbsocket.IWSMessageHandler;
import com.zjw.zy.heart.wbsocket.WsDispatcher;
import com.zjw.zy.heart.wbsocket.WsSender;
import com.zjw.zy.heart.wbsocket.socket.WsMessage;
import jakarta.websocket.Session;
import lombok.NonNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class C2CTransServiceImpl implements IC2CTransService, IWSMessageHandler, IWSConnectHandler {

    private static final String TAG = "C2CTransServiceImpl";

    private static final String C2C_KEY_PREF = "C2C_KEY_PREF_";

    private IUserPool userPool;

    private RedisTemplate<String, WsMessage> redisTemplate;

    @Override
    public void trans(WsMessage message) {
        LogUtils.d(TAG, "trans() called with: message = [" + message + "]");
        Session session = userPool.querySession(message.getTo());
        boolean success = WsSender.sendToClient(session, message);
        LogUtils.d(TAG, "trans result " + success);
        if (success) {
            onTransSuccess(message);
        } else {
            onTransFailed(message);
        }
    }

    private void onTransFailed(WsMessage message) {
        if (message.getInfo().startsWith(WsMessage.CLIENT_TO_CLIENT_INFO)) {
            Session self = userPool.querySession(message.getFrom());
            message.setInfo(WsMessage.CLIENT_TO_CLIENT_FAIL_INFO);
            WsSender.sendToClient(self, message);
            return;
        }

        if (message.getInfo().startsWith(WsMessage.CLIENT_TO_CLIENT_STRONG_INFO)) {
            LogUtils.d(TAG, "strong c2c and cache " + message);
            ListOperations<String, WsMessage> ops = redisTemplate.opsForList();

            ops.leftPush(C2C_KEY_PREF + message.getTo(), message);
        }
    }

    private void onTransFail(WsMessage message) {
        Session self = userPool.querySession(message.getFrom());
        message.setInfo(WsMessage.CLIENT_TO_CLIENT_FAIL_INFO);
        WsSender.sendToClient(self, message);
    }

    @Override
    public void onHandleWsMessage(@NonNull WsMessage message) {
        trans(message);
    }

    @Override
    public boolean onInterceptWsMessage(@NonNull WsMessage message) {
        String info = message.getInfo();
        return info.startsWith(WsMessage.CLIENT_TO_CLIENT_INFO) || info.startsWith(WsMessage.CLIENT_TO_CLIENT_STRONG_INFO);
    }

    @Override
    public boolean onInterceptOpen(Session session) {
        return true;
    }

    @Override
    public void onHandleOpen(Session session, String username) {
        ListOperations<String, WsMessage> ops = redisTemplate.opsForList();
        List<WsMessage> cache = ops.range(C2C_KEY_PREF + username, 0, -1);
        LogUtils.d(TAG, "cache strong- c2c ->" + username);
        if (cache == null || cache.isEmpty()) {
            return;
        }
        WsMessage message = WsMessage.obtain(WsMessage.CLIENT_TO_CLIENT_STRONG_CACHE_INFO);
        message.setPayload(cache);
        boolean success = WsSender.convertAndSendToClient(session, message);
        if (success) {
            Boolean delete = redisTemplate.delete(C2C_KEY_PREF + username);
            LogUtils.d(TAG, "delete c2c cache " + delete);
        }
    }

    private void onTransSuccess(WsMessage message) {
        //do nothing
    }

    @Autowired
    public void registerWsMessage(WsDispatcher dispatcher) {
        dispatcher.addWsMessageInterceptor(this);
        dispatcher.addWsConnectInterceptor(this);
    }

    @Autowired
    public void setUserPool(IUserPool userPool) {
        this.userPool = userPool;
    }


    @Autowired
    @Qualifier("c2c-cache")
    public void setRedisTemplate(RedisTemplate<String, WsMessage> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }
}
